home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
compress
/
unzip531.zip
/
amiga
/
flate.a
< prev
next >
Wrap
Text File
|
1997-04-20
|
16KB
|
440 lines
; Not copyrighted by Paul Kienitz, 20 June 94. Last modified 21 Feb 96.
;
; 68000 assembly language version of inflate_codes(), for Amiga. Prototype:
;
; int inflate_codes(__GPRO__ struct huft *tl, struct huft *td,
; int bl, int bd);
;
; Where __GPRO__ expands to "struct Globals *G," if REENTRANT is defined,
; otherwise to nothing. In the latter case G is a global variable.
;
; Define the symbol FUNZIP if this is for fUnZip. It overrides REENTRANT.
;
; Define AZTEC to use the Aztec C macro version of getc() instead of the
; library getc() with FUNZIP. AZTEC is ignored if FUNZIP is not defined.
;
; Define NO_CHECK_EOF to not use the fancy paranoid version of NEEDBITS --
; this is equivalent to removing the #define CHECK_EOF from inflate.c.
;
; Define INT16 if ints are short, otherwise it assumes ints are long.
;
; *DO NOT* define WSIZE -- this only works with the default value of 32K.
IFD INT16
MOVINT MACRO
move.w \1,\2
ENDM
INTSIZE equ 2
ELSE ; !INT16
MOVINT MACRO
move.l \1,\2
ENDM
INTSIZE equ 4
ENDC
IFD REENTRANT
IFND FUNZIP
REENT_G equ 1
ENDC
ENDC
; struct huft is defined as follows:
;
; struct huft {
; uch e; /* number of extra bits or operation */
; uch b; /* number of bits in this code or subcode */
; union {
; ush n; /* literal, length base, or distance base */
; struct huft *t; /* pointer to next level of table */
; } v;
; }; /* sizeof(struct huft) == 6 */
;
; so here we define the offsets of the various members of this struct:
h_e equ 0
h_b equ 1
h_n equ 2
h_t equ 2
SIZEOF_HUFT equ 6
; The following include file is generated from globals.h, and gives us equates
; that give the offsets in struct Globals of the fields we use, which are:
; ulg bb
; unsigned int bk, wp
; (either array of or pointer to unsigned char) slide
; For fUnZip:
; FILE *in
; For regular UnZip but not fUnZip:
; int incnt, mem_mode
; long csize
; uch *inptr
; It also defines a value SIZEOF_slide, which tells us whether the appropriate
; slide field in G (either area.Slide or redirect_pointer) is a pointer or an
; array instance. It is 4 in the former case and a large value in the latter.
; Lastly, this include will define CRYPT as 1 if appropriate.
IFD FUNZIP
INCLUDE "amiga/G_offs.fa"
ELSE
INCLUDE "amiga/G_offs.a"
ENDC
; G.bb is the global buffer that holds bits from the huffman code stream, which
; we cache in the register variable b. G.bk is the number of valid bits in it,
; which we cache in k. The macros NEEDBITS(n) and DUMPBITS(n) have side effects
; on b and k.
IFD REENT_G
G_SIZE equ 4
G_PUSH MACRO ; this macro passes "__G__" to functions
move.l G,-(sp)
ENDM
ELSE
xref _G ; struct Globals
G_SIZE equ 0
G_PUSH MACRO
ds.b 0 ; does nothing; the assembler dislikes MACRO ENDM
ENDM
ENDC ; REENT_G
xref _mask_bits ; const ush near mask_bits[17];
IFD FUNZIP
IF CRYPT
xref _encrypted ; int -- boolean flag
xref _update_keys ; int update_keys(__GPRO__ int)
xref _decrypt_byte ; int decrypt_byte(__GPRO)
ENDC ; CRYPT
ELSE ; !FUNZIP
xref _memflush ; int memflush(__GPRO__ uch *, ulg)
xref _readbyte ; int readbyte(__GPRO)
ENDC ; FUNZIP
xref _getc ; int getc(FILE *)
xref _flush ; if FUNZIP: int flush(__GPRO__ ulg)
; else: int flush(__GPRO__ uch *, ulg *, int)
; Here are our register variables.
b equr d2 ; ulg
k equr d3 ; ush <= 32
e equr d4 ; ush < 256 for most use
w equr d5 ; unsigned int
n equr d6 ; ush
d equr d7 ; unsigned int
; We always maintain w and d as valid unsigned longs, though they may be short.
t equr a2 ; struct huft *
mask equr a3 ; ush *
G equr a6 ; struct Globals *
; Couple other items we need:
savregs reg d2-d7/a2/a3/a6
WSIZE equ $8000 ; 32k... be careful not to treat as negative!
EOF equ -1
IFD FUNZIP
; This does getc(in). Aztec version is based on #define getc(fp) in stdio.h
IFD AZTEC
xref __filbuf
GETC MACRO
move.l in(G),a0
move.l (a0),a1 ; in->_bp
cmp.l 4(a0),a1 ; in->_bend
blo.s gci\@
move.l a0,-(sp)
jsr __filbuf
addq #4,sp
bra.s gce\@
gci\@: moveq #0,d0 ; must be valid as longword
move.b (a1)+,d0
move.l a1,(a0)
gce\@:
ENDM
ELSE ; !AZTEC
GETC MACRO
move.l in(G),-(sp)
jsr _getc
addq #4,sp
ENDM
ENDC ; AZTEC
ENDC ; FUNZIP
; Input depends on the NEXTBYTE macro. This exists in three different forms.
; The first two are for fUnZip, with and without decryption. The last is for
; regular UnZip with or without decryption. The resulting byte is returned
; in d0 as a longword, and d1, a0, and a1 are clobbered.
; FLUSH also has different forms for UnZip and fUnZip. Arg must be a longword.
; The same scratch registers are trashed.
IFD FUNZIP
NEXTBYTE MACRO
GETC
IF CRYPT
tst.w _encrypted+INTSIZE-2 ; test low word if long
beq.s nbe\@
MOVINT d0,-(sp) ; save thru next call
G_PUSH
jsr _decrypt_byte
eor.w d0,G_SIZE+INTSIZE-2(sp) ; becomes arg to update_keys
jsr _update_keys
addq #INTSIZE+G_SIZE,sp
nbe\@:
IFEQ INTSIZE-2
ext.l d0 ; assert -1 <= d0 <= 255
ENDC
ENDC ; !CRYPT
ENDM
FLUSH MACRO
move.l \1,-(sp)
G_PUSH
jsr _flush
addq #4+G_SIZE,sp
ENDM
ELSE ; !FUNZIP
NEXTBYTE MACRO
;; subq.l #1,csize(G)
;; bge.s nbg\@
;; moveq #EOF,d0
;; bra.s nbe\@
nbg\@: subq.w #1,incnt+INTSIZE-2(G) ; treat as short
bge.s nbs\@
G_PUSH
jsr _readbyte
IFNE G_SIZE
addq #G_SIZE,sp
ENDC
bra.s nbe\@
nbs\@: moveq #0,d0
move.l inptr(G),a0
move.b (a0)+,d0
move.l a0,inptr(G)
nbe\@:
ENDM
FLUSH MACRO
MOVINT #0,-(sp) ; unshrink flag: always false
move.l \1,-(sp) ; length
IFGT SIZEOF_slide-4
pea slide(G) ; buffer to flush
ELSE
move.l slide(G),-(sp)
ENDC
G_PUSH
tst.w mem_mode+INTSIZE-2(G) ; test lower word if long
beq.s fm\@
jsr _memflush ; ignores the unshrink flag
bra.s fe\@
fm\@: jsr _flush
fe\@: lea 8+INTSIZE+G_SIZE(sp),sp
ENDM
ENDC ; ?FUNZIP
; Here are the two bit-grabbing macros, defined in their NO_CHECK_EOF form:
;
; #define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE)<<k;k+=8;}}
; #define DUMPBITS(n) {b>>=(n);k-=(n);}
;
; Without NO_CHECK_EOF, NEEDBITS reads like this:
;
; {while(k<(n)){int c=NEXTBYTE;if(c==EOF)return 1;b|=((ulg)c)<<k;k+=8;}}
;
; NEEDBITS clobbers d0, d1, a0, and a1, none of which can be used as the arg
; to the macro specifying the number of bits. The arg can be a shortword memory
; address, or d2-d7. The result is copied into d1 as a word ready for masking.
; DUMPBITS has no side effects; the arg must be a d-register (or immediate in the
; range 1-8?) and only the lower byte is significant.
NEEDBITS MACRO
nb\@: cmp.w \1,k ; assert 0 < k <= 32 ... arg may be 0
bhs.s ne\@
NEXTBYTE ; returns in d0.l
IFND NO_CHECK_EOF
cmp.w #EOF,d0
bne.s nok\@
moveq #1,d0 ; PK_WARN?
bra return
ENDC ; !NO_CHECK_EOF
nok\@: lsl.l k,d0
or.l d0,b
addq.w #8,k
bra.s nb\@
ne\@: move.w b,d1
ENDM
DUMPBITS MACRO
lsr.l \1,b ; upper bits of \1 are ignored??
sub.b \1,k
ENDM
; ******************************************************************************
; Here we go, finally:
xdef _inflate_codes
_inflate_codes:
link a5,#-4
movem.l savregs,-(sp)
; 8(a5) = tl, 12(a5) = td, 16(a5) = bl, 18|20(a5) = bd... add 4 for REENT_G
; -2(a5) = ml, -4(a5) = md. Here we cache some globals and args:
IFD REENT_G
move.l 8(a5),G
ELSE
;; move.l _G,G ; old global pointer version
lea _G,G ; G is now a global instance
ENDC
lea _mask_bits,mask
move.l bb(G),b
MOVINT bk(G),k
IFD INT16
moveq #0,w ; keep this usable as longword
ENDC
MOVINT wp(G),w
moveq #0,e ; keep this usable as longword too
MOVINT 16+G_SIZE(a5),d0
add.w d0,d0
move.w (mask,d0.w),-2(a5) ; ml = mask_bits[bl]
MOVINT 16+INTSIZE+G_SIZE(a5),d0
add.w d0,d0
move.w (mask,d0.w),-4(a5) ; md = mask_bits[bd]
main_loop:
NEEDBITS 14+INTSIZE+G_SIZE(a5) ; bl, lower word if long
and.w -2(a5),d1 ; ml
mulu #SIZEOF_HUFT,d1
move.l 8+G_SIZE(a5),a0 ; tl
lea (a0,d1.l),t
move.b h_e(t),e
cmp.w #16,e
bls.s topdmp
intop: moveq #1,d0
cmp.w #99,e
beq return ; error in zipfile
move.b h_b(t),d0
DUMPBITS d0
sub.w #16,e
NEEDBITS e
move.w e,d0
add.w d0,d0
and.w (mask,d0.w),d1
mulu #SIZEOF_HUFT,d1
move.l h_t(t),a0
lea (a0,d1.l),t
move.b h_e(t),e
cmp.w #16,e
bgt.s intop
topdmp: move.b h_b(t),d0
DUMPBITS d0
cmp.w #16,e ; is this huffman code a literal?
bne lenchk ; no
move.w h_n(t),d0 ; yes
IFGT SIZEOF_slide-4
lea slide(G),a0
ELSE
move.l slide(G),a0
ENDC
move.b d0,(a0,w.l) ; stick in the decoded byte
addq.w #1,w
cmp.w #WSIZE,w
blo main_loop
FLUSH w
moveq #0,w
bra main_loop ; do some more
lenchk: cmp.w #15,e ; is it an end-of-block code?
beq finish ; if yes, we're done
NEEDBITS e ; no: we have a duplicate string
move.w e,d0
add.w d0,d0
and.w (mask,d0.w),d1
move.w h_n(t),n
add.w d1,n ; length of block to copy
DUMPBITS e
NEEDBITS 14+(2*INTSIZE)+G_SIZE(a5) ; bd, lower word if long
and.w -4(a5),d1 ; md
mulu #SIZEOF_HUFT,d1
move.l 12+G_SIZE(a5),a0 ; td
lea (a0,d1.l),t
move.b h_e(t),e
cmp.w #16,e
bls.s middmp
inmid: moveq #1,d0
cmp.w #99,e
beq return ; error in zipfile
move.b h_b(t),d0
DUMPBITS d0
sub.w #16,e
NEEDBITS e
move.w e,d0
add.w d0,d0
and.w (mask,d0.w),d1
mulu #SIZEOF_HUFT,d1
move.l h_t(t),a0
lea (a0,d1.l),t
move.b h_e(t),e
cmp.w #16,e
bgt.s inmid
middmp: move.b h_b(t),d0
DUMPBITS d0
NEEDBITS e
move.w e,d0
add.w d0,d0
and.w (mask,d0.w),d1
move.l w,d
sub.w h_n(t),d
sub.w d1,d ; distance back to block to copy
DUMPBITS e
indup: move.w #WSIZE,e ; violate the e < 256 rule
and.w #WSIZE-1,d
cmp.w d,w
blo.s ddgw
sub.w w,e
bra.s dadw
ddgw: sub.w d,e
dadw: cmp.w n,e
bls.s delen
move.w n,e
delen: sub.w e,n ; size of sub-block to copy
IFGT SIZEOF_slide-4
lea slide(G),a0
ELSE
move.l slide(G),a0
ENDC
move.l a0,a1
add.l w,a0 ; w and d are valid longwords
add.l d,a1
move.w e,d0
subq #1,d0 ; assert >= 0 if sign extended
dspin: move.b (a1)+,(a0)+ ; string is probably short, so
dbra d0,dspin ; don't use any fancier copy method
add.w e,w
add.w e,d
cmp.w #WSIZE,w
blo.s dnfl
FLUSH w
moveq #0,w
dnfl: tst.w n ; need to do more sub-blocks?
bne indup ; yes
moveq #0,e ; restore zeroness in upper bytes
bra main_loop ; do some more
finish: MOVINT w,wp(G) ; restore cached globals
MOVINT k,bk(G)
move.l b,bb(G)
moveq #0,d0 ; return "no error"
return: movem.l (sp)+,savregs
unlk a5
rts